#pragma once

#include "Matrix.hpp"
namespace zzz{
template <typename T>
class Matrix<3, 3, T> : public MatrixBase<3, 3, T>
{
public:
  Matrix(){}
  Matrix(const Matrix<3, 3, T> &mat):MatrixBase<3, 3, T>(mat){}
  Matrix(const MatrixBase<3, 3, T> &mat):MatrixBase<3, 3, T>(mat){}
  template<typename T1> explicit Matrix<3, 3, T>(const MatrixBase<3, 3,T1>& a):MatrixBase<3, 3, T>(a) {}
  template<typename T1> explicit Matrix<3, 3, T>(const Matrix<3, 3,T1>& a):MatrixBase<3, 3, T>(a) {}
  template<typename T1> explicit Matrix<3, 3, T>(const T1 *p):MatrixBase<3, 3, T>(p) {}
  explicit Matrix<3, 3, T>(const T &a):MatrixBase<3, 3, T>(a){}

  Matrix(const T& a,const T& b,const T& c,const T& d,const T& e,const T& f,const T& g,const T& h,const T& i)
  {
    T* v=Data();
    v[0]=a; v[1]=b; v[2]=c;
    v[3]=d; v[4]=e; v[5]=f;
    v[6]=g; v[7]=h; v[8]=i;
  }
  explicit Matrix(const T *p)
  {
    T* v=Data();
    v[0]=p[0];  v[1]=p[1];  v[2]=p[2];
    v[3]=p[3];  v[4]=p[4];  v[5]=p[5];
    v[6]=p[6];  v[7]=p[7];  v[8]=p[8];
  }
  Matrix(const Vector<3, T>& a,const Vector<3, T>& b,const Vector<3, T>& c)
  {
    T* v=Data();
    v[0]=a[0]; v[1]=a[1]; v[2]=a[2];
    v[3]=b[0]; v[4]=b[1]; v[5]=b[2];
    v[6]=c[0]; v[7]=c[1]; v[8]=c[2];
  }
  explicit Matrix(const Vector<3, T> *a)
  {
    T* v=Data();
    v[0]=a[0][0]; v[1]=a[0][1]; v[2]=a[0][2];
    v[3]=a[1][0]; v[4]=a[1][1]; v[5]=a[1][2];
    v[6]=a[2][0]; v[7]=a[2][1]; v[8]=a[2][2];
  }

  //assign
  inline const Matrix<3, 3, T> &operator=(const Matrix<3, 3, T>& a){MatrixBase<3, 3, T>::operator =(a); return *this;}
  using MatrixBase<3, 3, T>::operator=;
  using MatrixBase<3, 3, T>::Data;

  //alias
  const T& m00() const {return Data()[0];}
  const T& m01() const {return Data()[1];}
  const T& m02() const {return Data()[2];}
  const T& m10() const {return Data()[3];}
  const T& m11() const {return Data()[4];}
  const T& m12() const {return Data()[5];}
  const T& m20() const {return Data()[6];}
  const T& m21() const {return Data()[7];}
  const T& m22() const {return Data()[8];}
  const T& v0() const {return Data()[0];}
  const T& v1() const {return Data()[1];}
  const T& v2() const {return Data()[2];}
  const T& v3() const {return Data()[3];}
  const T& v4() const {return Data()[4];}
  const T& v5() const {return Data()[5];}
  const T& v6() const {return Data()[6];}
  const T& v7() const {return Data()[7];}
  const T& v8() const {return Data()[8];}
  T& m00() {return Data()[0];}
  T& m01() {return Data()[1];}
  T& m02() {return Data()[2];}
  T& m10() {return Data()[3];}
  T& m11() {return Data()[4];}
  T& m12() {return Data()[5];}
  T& m20() {return Data()[6];}
  T& m21() {return Data()[7];}
  T& m22() {return Data()[8];}
  T& v0() {return Data()[0];}
  T& v1() {return Data()[1];}
  T& v2() {return Data()[2];}
  T& v3() {return Data()[3];}
  T& v4() {return Data()[4];}
  T& v5() {return Data()[5];}
  T& v6() {return Data()[6];}
  T& v7() {return Data()[7];}
  T& v8() {return Data()[8];}
};

typedef Matrix<3, 3,zint8> Matrix3x3i8;
typedef Matrix<3, 3,zuint8> Matrix3x3ui8;
typedef Matrix<3, 3,zint16> Matrix3x3i16;
typedef Matrix<3, 3,zuint16> Matrix3x3ui16;
typedef Matrix<3, 3,zint32> Matrix3x3i32;
typedef Matrix<3, 3,zuint32> Matrix3x3ui32;
typedef Matrix<3, 3,zint64> Matrix3x3i64;
typedef Matrix<3, 3,zuint64> Matrix3x3ui64;
typedef Matrix<3, 3,zfloat32> Matrix3x3f32;
typedef Matrix<3, 3,zfloat64> Matrix3x3f64;

typedef Matrix<3, 3,zuint> Matrix3x3ui;
typedef Matrix<3, 3,int> Matrix3x3i;
typedef Matrix<3, 3,float> Matrix3x3f;
typedef Matrix<3, 3,double> Matrix3x3d;
}
